package org.example.im.common.codec;

import io.netty.buffer.ByteBuf;
import lombok.RequiredArgsConstructor;
import org.example.im.bean.protocol.CommandType;
import org.example.im.bean.protocol.Packet;
import org.example.im.common.exception.IMBindException;
import org.example.im.common.serialize.Serializer;
import org.example.im.common.serialize.SerializerFactory;
import org.example.im.common.serialize.SerializerType;
import org.example.im.common.util.EnumUtil;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * @author dingrui
 * @since 2022/2/10
 * @description
 * @see org.example.im.bean.protocol.Packet
 */
@Component
@RequiredArgsConstructor
public class PacketCodec implements Codec {

    public static final int MAGIC_NUMBER = 0x1;

    private final SerializerFactory serializerFactory;

    @Override
    public void encode(Packet packet, ByteBuf byteBuf) {
        // 序列化java bean
        SerializerType serializerType = SerializerType.JSON;
        Serializer serializer = null;
        if (Objects.isNull(serializer = this.serializerFactory.create(serializerType))) {
            serializerType = EnumUtil.random(SerializerType.class);
            serializer = this.serializerFactory.create(serializerType);
            if (Objects.isNull(serializer)) throw new IMBindException("没有序列化器的具体实现");
        }
        byte[] bytes = serializer.serialize(packet);
        // 编码
        byteBuf.writeInt(MAGIC_NUMBER); // 4byte
        byteBuf.writeByte(packet.getVersion()); // 1byte
        byteBuf.writeByte(SerializerType.JSON.getCode()); // 1byte
        byteBuf.writeByte(packet.getCommandType().getCode()); // 1byte
        byteBuf.writeInt(bytes.length); // 4byte
        byteBuf.writeBytes(bytes); // n
    }

    @Override
    public Packet decode(ByteBuf byteBuf) {
        byteBuf.skipBytes(4); // magic number
        byteBuf.skipBytes(1); // version
        byte serializerType = byteBuf.readByte();
        byte commandType = byteBuf.readByte();
        int packLen = byteBuf.readInt();
        byte[] bytes = new byte[packLen];
        byteBuf.readBytes(bytes);
        Class<? extends Packet> packetType = CommandType.getPacketTypeByCommandCode(commandType);
        if (Objects.isNull(packetType)) return null;
        Serializer serializer = this.serializerFactory.create(SerializerType.getByCode(serializerType));
        if (Objects.isNull(serializer)) return null;
        return serializer.deserialize(bytes, packetType);
    }
}
